#include <cubefs/api/api.hpp>
#include <natives.h>
#include <decls.hpp>
#include <exceptions.hpp>

#include <cubefs/core/tools/types/dispatcher.hpp>

#define CUBEFS_SOURCE "operation.cpp:" CUBEFS_AT

using namespace cubefs::api;
using namespace cubefs::tools;

using namespace std;

JNIEXPORT jlong JNICALL REFLECTION_PKG(Operation, owner) (JNIEnv *env, jclass, jlong handle) {
    CUBEFS_EXC_BEGIN
    Operation* op = Handle2Ptr<Operation>(handle);
    return Ptr2Handle(op->owner());
    CUBEFS_EXC_HANDLE
    return 0;
}

JNIEXPORT jlong JNICALL REFLECTION_PKG(Operation, GetReturnType) (JNIEnv *env, jclass, jlong handle) {
    CUBEFS_EXC_BEGIN

    Operation* op = Handle2Ptr<Operation>(handle);
    return Ptr2Handle(op->GetReturnType());

    CUBEFS_EXC_HANDLE
    return 0;
}

JNIEXPORT jint JNICALL REFLECTION_PKG(Operation, GetArgumentsCount) (JNIEnv *env, jclass, jlong handle) {
    CUBEFS_EXC_BEGIN
    Operation* op = Handle2Ptr<Operation>(handle);
    return op->GetArgumentsCount();
    CUBEFS_EXC_HANDLE
    return 0;
}

JNIEXPORT jlong JNICALL REFLECTION_PKG(Operation, GetArgument__JI) (JNIEnv *env, jclass, jlong handle, jint idx) {
    CUBEFS_EXC_BEGIN
    Operation* op = Handle2Ptr<Operation>(handle);
    return Ptr2Handle(op->GetArgument(idx));
    CUBEFS_EXC_HANDLE
    return 0;
}

JNIEXPORT jlong JNICALL REFLECTION_PKG(Operation, GetArgument__JLjava_lang_String_2) (JNIEnv *env, jclass, jlong handle, jstring name) {
    CUBEFS_EXC_BEGIN
    Operation* op = Handle2Ptr<Operation>(handle);

    const char *str = env->GetStringUTFChars(name, NULL);
    if (str == NULL) {
        return 0; /* OutOfMemoryError already thrown */
    }

    jlong h0 = Ptr2Handle(op->GetArgument(str));

    env->ReleaseStringUTFChars(name, str);

    return h0;
    CUBEFS_EXC_HANDLE
    return 0;
}

JNIEXPORT jstring JNICALL REFLECTION_PKG(Operation, name) (JNIEnv *env, jclass, jlong handle) {
    CUBEFS_EXC_BEGIN
    Operation* op = Handle2Ptr<Operation>(handle);
    return env->NewStringUTF(op->name().c_str());
    CUBEFS_EXC_HANDLE
    return NULL;
}


JNIEXPORT jlong JNICALL REFLECTION_PKG(Operation, invoke) (JNIEnv *env, jclass, jlong handle, jlong tgt, jlong args) {
    CUBEFS_EXC_BEGIN

    Operation* op = Handle2Ptr<Operation>(handle);

    Typed* target = Handle2Ptr<Typed>(tgt, false);

    StaticListOfTyped* list = Handle2Ptr<StaticListOfTyped>(args, false);

    int cnt = op->GetArgumentsCount();

    if (cnt > 0) {
        if (list != NULL) {
            if (list->size() != cnt) {
                throw CubefsException(CUBEFS_SOURCE, "Invaling number of argiments for this operation");
            }
        }
        else {
            throw NullPointerException(CUBEFS_SOURCE, "Arguments list can't be null for this operation");
        }
    }

    if (target == NULL && !op->IsStatic()) {
        throw NullPointerException(CUBEFS_SOURCE, "Target nust not be null for non-static operations");
    }

    Typed* result = op->invoke(target, list);

    return Ptr2Handle(result);
    CUBEFS_EXC_HANDLE
    return 0;
}

JNIEXPORT jboolean JNICALL REFLECTION_PKG(Operation, IsStatic) (JNIEnv *env, jclass, jlong handle) {
    CUBEFS_EXC_BEGIN
    Operation* op = Handle2Ptr<Operation>(handle);
    return op->IsStatic();
    CUBEFS_EXC_HANDLE
    return false;
}

JNIEXPORT jboolean JNICALL REFLECTION_PKG(Operation, IsTyped) (JNIEnv *env, jclass, jlong handle) {
    CUBEFS_EXC_BEGIN
    Operation* op = Handle2Ptr<Operation>(handle);
    return false; //op->IsTyped();
    CUBEFS_EXC_HANDLE
    return false;
}


JNIEXPORT jstring JNICALL REFLECTION_PKG(Parameter, name) (JNIEnv *env, jclass, jlong handle) {
    CUBEFS_EXC_BEGIN

    Argument* par = Handle2Ptr<Argument>(handle);
    return env->NewStringUTF(par->name().c_str());

    CUBEFS_EXC_HANDLE
    return NULL;
}

JNIEXPORT jlong JNICALL REFLECTION_PKG(Parameter, GetParameterType) (JNIEnv *env, jclass, jlong handle) {
    CUBEFS_EXC_BEGIN

    Argument* par = Handle2Ptr<Argument>(handle);
    
    return Ptr2Handle(par->GetParameterType());
    CUBEFS_EXC_HANDLE
    return 0;
}




#undef CUBEFS_SOURCE

